-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JIT: Do not propagate some constants #70378
Conversation
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch Issue DetailsLet's see what Diffs think. This might ruin some Lowering optimizations which expect constant values but I expect to see more benefits than regressions from this. Closes #70355
|
src/coreclr/jit/assertionprop.cpp
Outdated
keepPropagating = true; | ||
} | ||
#elif TARGET_XARCH | ||
// All integer constants are cheap to materialize on xarch | ||
keepPropagating = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this right?
Those that fit in 8-bits (generally sign-extended, but sometimes zero-extended) are often (but not always) containable, but if its 2-
, 4-
, or 8-bytes` then it generally needs a separate instruction and is more expensive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tannergooding I agree but in this PR I only try to avoid memory loads - there are too many pitfalls this PR can't take into account like register-pressure, cached constants which live across calls on ABIs without callee-saved regs, etc - it's just a quick heuristic at this point
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be worth logging an issue for someone to experiment here a bit.
I'd expect that most cases of explicit mov reg, imm
are better handled by hoisting as it impacts the size of the loop and doesn't allow optimizations in many scenarios.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure thing, I am actually going to spend some time on it after this PR because it's even more important for ARM where it might ends up with 4 mov per single constant
PerfScore diffs
|
@dotnet/jit-contrib @tannergooding @jakobbotsch PTAL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a reasonable fix to me.
src/coreclr/jit/assertionprop.cpp
Outdated
const unsigned ssaNum = GetSsaNumForLocalVarDef(tree); | ||
if (ssaNum != SsaConfig::RESERVED_SSA_NUM) | ||
{ | ||
BasicBlock* defBlock = lvaTable[lclNum].GetPerSsaData(ssaNum)->GetBlock(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style nit: lvaTable[lclNum].
-> lvaGetDesc(lclNum)->
.
General comment on the algorithm: this walks only one step up in the def chain, so if we have something like this:
var a = const;
for (...) {
var b = a;
Use(b);
}
We will still propagate const
to Use
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SingleAccretion I don't see why it would.
When we're at Use(b) and we query SsaData()->Block from b we get a
's Block and it leads to "avoid propagating" path
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, actually for your case b
is going to be replaced with a
in an earlier phase VN based copy prop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we're at
Use(b)
and we querySsaData()->Block
fromb
we geta
's Block and it leads to "avoid propagating" path
If I annotate this with blocks:
BB01:
var a = const;
for (...) {
BB02:
var b = a; // b:d:1
Use(b); // b:u:1
}
I am pretty sure that when we query the def block for b:u:1
, we'd get BB02
, since the def b:d:1
occurs inside it.
Ah, actually for your case
b
is going to be replaced witha
in an earlier phase VN based copy prop
I agree that copy propagation helps us here; not sure by how much because of the liveness constraints it has.
In any case, I also agree that there is no reason, for now, to complicate the code with a full UD chain walk, because we are pretty much targeting people hoisting constants out of loops by hands.
Co-authored-by: Tanner Gooding <[email protected]>
@SingleAccretion does it look good now? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, code changes look good.
I did not look at the regressions; presuming the are "expected".
Yeah, I ran SPMI with |
Let's see what Diffs think.
Jit always try to propagate single-def constant values but it's not always a good thing, e.g. constant vectors and doubles end up as memory loads and we don't want to propagate them inside loops etc. Same about long integers (e.g. handles) on arm64
This might ruin some Lowering optimizations which expect constant values but I expect to see more benefits than regressions from this.
Closes #70355